{*******************************************************}
{                                                       }
{       RaPagedGrid                                     }
{                                                       }
{       Copyright (C) 2006 http://www.bugua.net         }
{                                                       }
{*******************************************************}

unit RaPagedGrid;

interface

uses
  SysUtils, Classes, Controls, Grids{Uses the Grid}, DB{Uses the DB};

type
  {Goto Ways}
  TGotoWay=(gwFirst,gwPrior,gwNext,gwLast,gwNone);
  {Event Declare}
  TOnPageChange=procedure(Sender:TObject;Page:Integer)of object;
  {Class Inherit}
  TRaPagedGrid = class(TStringGrid)
  private
    {DataSource}
    fDataSource: TDataSource;
    {Table's Page Count}
    fPageCount: Integer;
    {Current Page}
    fPageNo: Integer;
    {Display Fields' List}
    fFieldList: TStringList;
    {Max Rows in a Page}
    fMaxRows: Integer;
    {The Page Change Event}
    fOnPageChange: TOnPageChange;
    {The Cell (0,0)}
    fCellZero: String;
    {Goto Method}
    fMethod: TGotoWay;
    {Set the Number of Current Page}
    procedure SetPageNo(const Value: Integer);
    {Assign Field List}
    procedure SetFieldList(const Value: TStringList);
    {Return the Page Count}
    function GetPageCount: Integer;
  protected
    {Create Table Title(Head)}
    procedure GetTitle;
    {Clear Grid}
    procedure ClearGrid;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    {Show Data First Time, and Set PageNo to 1}
    procedure ShowData;
    {Get the Field list, must use this method}
    procedure GetFieldList;
    procedure AddField(const AFieldName,ADisplayName:string);
    procedure DeleteField(const AFieldName:string);
    procedure SetFieldName(const AFieldName,ADisplayName:String);
    procedure NavigatePage(GotoWay:TGotoWay);
    procedure Last;
    procedure First;
    procedure Prior;
    procedure Next;
  published
    {Goto Method}
    property GotoMethod:TGotoWay read fMethod write fMethod nodefault;
    {Cell(0,0)}
    property CellZero:String read fCellZero write fCellZero;
    {Event}
    property OnPageChange:TOnPageChange read fOnPageChange write fOnPageChange;
    {Property}
    property MaxRows:Integer read fMaxRows write fMaxRows default 10;
    property FieldList:TStringList read fFieldList write SetFieldList;
    property DataSource:TDataSource read fDataSource write fDataSource;
    property PageNo:Integer read fPageNo write SetPageNo default 1;
    property PageCount:Integer read GetPageCount write fPageCount;
  end;

procedure Register;

implementation

procedure Register;
begin
  {Regist component to Delphi}
  RegisterComponents('Rarnu Components', [TRaPagedGrid]);
end;

{ TRaPagedGrid }

{-------------------------------------------------------------------------------
  Procedure: TRaPagedGrid.AddField
  Author:    Rarnu
  DateTime:  2006.09.20
  Arguments: const AFieldName, ADisplayName: string
  Result:    None
-------------------------------------------------------------------------------}
procedure TRaPagedGrid.AddField(const AFieldName, ADisplayName: string);
begin
  {The Style of List is "FieldName=DisplayName"}
  self.fFieldList.Add(AFieldName+'='+ADisplayName);
end;

{-------------------------------------------------------------------------------
  Procedure: TRaPagedGrid.Create
  Author:    Rarnu
  DateTime:  2006.09.20
  Arguments: AOwner: TComponent
  Result:    None
-------------------------------------------------------------------------------}
constructor TRaPagedGrid.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  fFieldList:=TStringList.Create;
  fFieldList.Clear;
  {Set MaxRows' default value to 10}
  self.fMaxRows:=10;
  fPageNo:=1;
end;

{-------------------------------------------------------------------------------
  Procedure: TRaPagedGrid.GetTitle
  Author:    Rarnu
  DateTime:  2006.09.20
  Arguments: None
  Result:    None
-------------------------------------------------------------------------------}
procedure TRaPagedGrid.GetTitle;
var
  i:Integer;
  ColName:string;
  DispName:string;
  Xpo:Integer;
  ds:TDataSet;
begin
  if self.fDataSource=nil then Exit;
  ds:=self.fDataSource.DataSet;
  {Set Col Count to Fields' Count}
  self.ColCount:=self.fFieldList.Count+1;
  for i:=0 to self.fFieldList.Count-1 do
  begin
    {Get Equal Signal's Position}
    XPO:=Pos('=',self.fFieldList.Strings[i]);
    {Get Value Name}
    ColName:=Copy(self.fFieldList.Strings[i],1,xpo-1);
    DispName:=self.fFieldList.Values[ColName];
    {Set Title's Width}
    self.ColWidths[i+self.FixedCols]:=
      ds.FieldByName(ColName).DisplayWidth*self.Canvas.TextWidth('0');
    {Set Title's Caption}
    self.Cells[i+self.FixedCols,0]:=DispName;
  end;
end;

{-------------------------------------------------------------------------------
  Procedure: TRaPagedGrid.DeleteField
  Author:    Rarnu
  DateTime:  2006.09.20
  Arguments: const AFieldName: string
  Result:    None
-------------------------------------------------------------------------------}
procedure TRaPagedGrid.DeleteField(const AFieldName: string);
var
  i,Cnt:Integer;
  ColName:string;
  XPO:Integer;
begin
  Cnt:=Self.fFieldList.Count;
  for i:=0 to Cnt-1 do
  begin
    XPO:=Pos('=',self.fFieldList.Strings[i]);
    ColName:=Copy(Self.fFieldList.Strings[i],1,XPO-1);
    {If Gotten Value Name Equals to Field Name}
    if ColName=AFieldName then
    begin
      {Delete Current Item}
      self.fFieldList.Delete(i);
      Break;
    end;
  end;
end;

{-------------------------------------------------------------------------------
  Procedure: TRaPagedGrid.Destroy
  Author:    Rarnu
  DateTime:  2006.09.20
  Arguments: None
  Result:    None
-------------------------------------------------------------------------------}
destructor TRaPagedGrid.Destroy;
begin
  fFieldList.Free;
  fDataSource:=nil;
  inherited Destroy;
end;

{-------------------------------------------------------------------------------
  Procedure: TRaPagedGrid.GetFieldList
  Author:    Rarnu
  DateTime:  2006.09.20
  Arguments: None
  Result:    None
-------------------------------------------------------------------------------}
procedure TRaPagedGrid.GetFieldList;
var
  i,FldCnt:Integer;
  FldName:string;
begin
  if self.fDataSource=nil then Exit;
  {Clear the Field List}
  Self.fFieldList.Clear;
  FldCnt:=self.fDataSource.DataSet.FieldCount;
  for i:=0 to FldCnt-1 do
  begin
    {Get Field Name and Copy it}
    FldName:=self.fDataSource.DataSet.Fields.Fields[i].DisplayName;
    self.fFieldList.Add(FldName+'='+FldName);
  end;
end;

{-------------------------------------------------------------------------------
  Procedure: TRaPagedGrid.SetFieldList
  Author:    Rarnu
  DateTime:  2006.09.20
  Arguments: const Value: TStringList
  Result:    None
-------------------------------------------------------------------------------}
procedure TRaPagedGrid.SetFieldList(const Value: TStringList);
begin
  {Assign Values, an Object must use "Assign" but not "="}
  fFieldList.Assign(Value);
end;

{-------------------------------------------------------------------------------
  Procedure: TRaPagedGrid.SetFieldName
  Author:    Rarnu
  DateTime:  2006.09.20
  Arguments: const AFieldName, ADisplayName: String
  Result:    None
-------------------------------------------------------------------------------}
procedure TRaPagedGrid.SetFieldName(const AFieldName,
  ADisplayName: String);
begin
  self.fFieldList.Values[AFieldName]:=ADisplayName;
end;

{-------------------------------------------------------------------------------
  Procedure: TRaPagedGrid.SetPageNo
  Author:    Rarnu
  DateTime:  2006.09.20
  Arguments: const Value: Integer
  Result:    None
-------------------------------------------------------------------------------}
procedure TRaPagedGrid.SetPageNo(const Value: Integer);
var
  RecNum:Integer;
  Rows:Integer;
  i:Integer;
  ColName:string;
  Xpo:Integer;
  ds:TDataSet;
begin
  if self.fDataSource=nil then Exit;
  ds:=self.fDataSource.DataSet;
  {Check DataSet is Actived ot not}
  if not ds.Active then exit;
  //if (self.fMethod=gwfirst)or(self.fMethod=gwlast)then exit;
  if fPageNo<1 then
  begin
    fPageNo:=1;
    Exit;
  end;
  if fPageNo>PageCount then
  begin
    fPageNo:=PageCount;
    exit;
  end;
  fPageNo := Value;
  {Get Page Count}
//  if ds.RecordCount=0 then
//    fPageCount:=1
//  else
//    fPageCount:=((ds.RecordCount-1) div fMaxRows)+1;
  {Count Current Record Number}
  if fPageNo<1 then
  begin
    fPageNo:=1;
    Exit;
  end;
  if fPageNo>PageCount then
  begin
    fPageNo:=PageCount;
    exit;
  end;
  RecNum:=(fPageNo-1)*fmaxRows+1;
  if RecNum>ds.RecordCount then exit;
  {Set Table's Current Record Number}
  if ds.RecordCount=0 then
    ds.Last
  else
    ds.RecNo:=RecNum;
  Rows:=0;
  {Set Rows Forward}
  self.RowCount:=self.fMaxRows+1;
  self.ClearGrid;
  while not ds.Eof do
  begin
    {Write Record Number to Grid Cell}
    if FixedCols<>0 then
      self.Cells[0,Rows+1]:=IntToStr(RecNum);
    for i:=0 to self.fFieldList.Count-1 do
    begin
      XPO:=Pos('=',self.fFieldList.Strings[i]);
      ColName:=Copy(self.fFieldList.Strings[i],1,xpo-1);
      {Get Data from Table and Write It to Grid}
      self.Cells[i+self.FixedCols,Rows+1]:=
        ds.FieldByName(ColName).AsString;
    end;
    Inc(Rows);
    Inc(RecNum);
    if Rows=fMaxRows then break;
    {dataSet's Pointer Move to Next Record}
    ds.Next;
  end;
  {Set Rows}
  if Rows=0 then
    self.RowCount:=2
  else
    self.RowCount:=Rows+1;
  {The Page Change Event Binding}
  if Assigned(OnPageChange) then
    OnPageChange(Self,fPageNo);
end;

{-------------------------------------------------------------------------------
  Procedure: TRaPagedGrid.ShowData
  Author:    Rarnu
  DateTime:  2006.09.20
  Arguments: None
  Result:    None
-------------------------------------------------------------------------------}
procedure TRaPagedGrid.ShowData;
begin
  if self.fDataSource=nil then Exit;
  self.ClearGrid;
  {Call GetTitle}
  self.GetTitle;
  PageNo:=1;
end;

{-------------------------------------------------------------------------------
  Procedure: TRaPagedGrid.GetPageCount
  Author:    Rarnu
  DateTime:  2006.09.20
  Arguments: None
  Result:    Integer
-------------------------------------------------------------------------------}
function TRaPagedGrid.GetPageCount: Integer;
var
  RowCnt:Integer;
begin
  Result:=0;
  if self.fDataSource=nil then Exit;
  {Get Table's Record Count}
  RowCnt:=self.fDataSource.DataSet.RecordCount;
  if RowCnt=0 then
    fPageCount:=1
  else
    fPageCount:=((RowCnt-1) div fMaxRows)+1;
  Result:=fPageCount;
end;

{-------------------------------------------------------------------------------
  Procedure: TRaPagedGrid.ClearGrid
  Author:    Rarnu
  DateTime:  2006.09.20
  Arguments: None
  Result:    None
-------------------------------------------------------------------------------}
procedure TRaPagedGrid.ClearGrid;
var
  i,j:Integer;
begin
  for i:=0 to self.ColCount-1 do
    for j:=1 to self.RowCount-1 do
      self.Cells[i,j]:='';
end;

procedure TRaPagedGrid.NavigatePage(GotoWay: TGotoWay);
begin
  case GotoWay of
    gwFirst:self.First;
    gwLast:self.Last;
    gwPrior:self.Prior;
    gwNext:self.Next;
  end;
  self.fMethod:=GotoWay;
end;

procedure TRaPagedGrid.First;
begin
  PageNo:=1;
end;

procedure TRaPagedGrid.Last;
var
  fNO:Integer;
begin
  fNo:=PageNo;
  while fNO<PageCount do
  begin
    self.Next;
    Inc(fNO);
  end;
end;

procedure TRaPagedGrid.Next;
begin
  PageNo:=PageNo+1;
end;

procedure TRaPagedGrid.Prior;
begin
  PageNo:=PageNo-1;
end;

end.
